<template>
  <div class="base">
    <el-popover
      placement="right"
      title=""
      :width="200"
      trigger="hover"
      content="this is content, this is content, this is content"
    >
      <template #reference>
        <div
          class="test"
          v-for="(item, index) in [{ name: 1 }, { name: 2 }]"
          :key="index"
          :id="`test${index}`"
        >
          {{ item.name }}
        </div>
      </template>
    </el-popover>

    <canvas id="webgl"></canvas>
    <div class="pannel">
      <span>XZ：{{ form.x?.toFixed(2) }},{{ form.z?.toFixed(2) }}</span>
      <el-button @click="resetCamera" type="primary">视角回正</el-button>
      <!-- <span @click="resetCamera" class="btn">视角回正</span> -->
      <span>注意：双击取点时相机缩放必须保持初始化一致</span>
    </div>
  </div>
</template>

<script setup>
import { reactive, onMounted, onUnmounted, ref } from "vue";
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
// import { CSS3DRenderer } from "three/examples/jsm/renderers/CSS3DRenderer.js";
import utils from "@/utils";
import * as dat from "lil-gui";
import createTag from "./util/createTag";
import createLine from "./util/flyLine";
import tagData from "./data/tagData";
import lineData from "./data/lineData";
import gsap from "gsap";
import EventBus from "./util/eventBus";
// ----------------------------变量合集--------------------------
let canvas = null;
let baseBox = null; // html元素用于监听网页大小变化时渲染的宽高变化
const scene = new THREE.Scene();
const sizes = {
  width: 800,
  height: 600,
  aspect() {
    return this.width / this.height;
  },
};
// 辅助线
const axesHelper = new THREE.AxesHelper(100);
const gridHelper = new THREE.GridHelper(1000, 500);
// scene.add(axesHelper);
// scene.add(gridHelper);

// 几何体
const geometry = new THREE.BoxGeometry(1000, 1, 500);
const material = new THREE.MeshBasicMaterial({
  color: 0x000000,
  transparent: true,
  opacity: 0.2,
});
const mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);

// --------------------------初始化------------------------------
let camera = null; // 相机
let controls = null; // 相机控制器
let renderer = null; // 渲染器
let css3dRenderer = null; // HTML元素转3D渲染器
// 初始化函数 再mounted之后渲染
const initial = () => {
  canvas = document.querySelector("#webgl");
  baseBox = document.querySelector(".base");
  sizes.width = baseBox.clientWidth;
  sizes.height = baseBox.clientHeight;

  // 渲染器设置
  renderer = new THREE.WebGLRenderer({
    canvas: canvas,
    antialias: true,
  });

  renderer.setSize(sizes.width, sizes.height);
  //设置canvas的像素比为当前设备的屏幕像素比或者2之间的最小值，避免高分屏下模糊
  renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
  renderer.setClearColor("#030738");

  // 相机设置
  camera = new THREE.PerspectiveCamera(75, sizes.aspect(), 0.1, 1000);
  // const cameraLength = 150
  // camera = new THREE.OrthographicCamera(
  //   -cameraLength * sizes.aspect(),
  //   cameraLength * sizes.aspect(),
  //   cameraLength,
  //   -cameraLength,
  //   0.1,
  //   1000
  // )
  camera.position.set(0, 200, 0);
  scene.add(camera);
  // 相机控制器设置
  controls = new OrbitControls(camera, canvas);
  controls.enableRotate = false; //旋转
  controls.enableZoom = true; //缩放
  controls.enableDamping = false; // 添加阻尼感

  // 初始化css3D加载器
  css3dRenderer = createTag.createRenderer(sizes, baseBox);
  tick();
};

// const clock = new THREE.Clock();
// let time = clock.getElapsedTime();
const tick = () => {
  // 更新所有飞线
  updateFly(1);

  controls.update();
  css3dRenderer.render(scene, camera);
  renderer.render(scene, camera);
  window.requestAnimationFrame(tick);
};

// ----------------------------业务代码--------------------------
// 0——初始化集合 加入场景scene
// 1——添加变电站标签 放入变电站组
// 2——添加相应线段 放入线段组
// 3——添加飞线
// const electricGroup = new THREE.Group(); // 所有组的集合
const tagGroup = new THREE.Group(); // 站点组
const lineGroup = new THREE.Group(); // 线段组
const flyGroup = new THREE.Group(); // 飞线组
const boxGroup = new THREE.Group(); // 小盒子组
const mainDataGroup = new THREE.Group(); // 主要文字组
const subDataGroup = new THREE.Group(); // 次要文字组

const vueTagGroup = new THREE.Group(); // 完全由已有模板元素组成的HTML转3D模型

scene.add(vueTagGroup);
scene.add(tagGroup);
scene.add(lineGroup);
scene.add(flyGroup);
scene.add(boxGroup);
scene.add(mainDataGroup);
scene.add(subDataGroup);

// 所有Vue标签转化
const vueTag = () => {
  const label = createTag.createTagFromVue("test0");
  vueTagGroup.add(label);
};
// 所有变电站标签
const tagAll = () => {
  tagData.forEach((item) => {
    const label = createTag.tagDiv(item);
    tagGroup.add(label);
  });
};
// 所有线段
const lineAll = () => {
  lineData.forEach((item) => {
    const line = createLine.createLine([...item.position]);
    lineGroup.add(line);
    boxAll(item);
    mainDataAll(item);
    subDataAll(item);
  });
  lineGroup.position.y = 0.5;
};
// 所有小盒子 item - 线段数据(lineData)
const boxAll = (item) => {
  if (item.boxList) {
    item.boxList.forEach((box) => {
      const boxMesh = createTag.boxDiv({
        name: box.name,
        x: box.position[0],
        z: box.position[1],
        borderColor: box.borderColor,
        background: box.background,
      });
      boxGroup.add(boxMesh);
    });
  }
};
// 所有主要文字 item - 线段数据(lineData.mainData)
const mainDataAll = (item) => {
  if (item.mainData) {
    const mainDataMesh = createTag.createMainData({
      name: item.mainData.name,
      value: item.mainData.value,
      x: item.mainData.position[0],
      z: item.mainData.position[1],
    });
    mainDataGroup.add(mainDataMesh);
  }
};
// 所有次要文字 item - 线段数据(lineData.subData)
const subDataAll = (item) => {
  if (item.subData) {
    const mesh = createTag.createSubData(item.subData);
    subDataGroup.add(mesh);
  }
};
// 所有飞线
const flyLine = () => {
  lineGroup.children.forEach((item) => {
    const fly = createLine.createFlyLine(item.points, 30);
    flyGroup.add(fly);
  });
  flyGroup.position.y = 0.6;
};
// 按帧更新飞线位置
const updateFly = (frame = 1) => {
  flyGroup.children.forEach((item) => {
    // console.log(item);
    if (item.index > item.indexMax) item.index = 0;
    item.index += frame;
    const newPoints = item.points.slice(item.index, item.index + item.number);
    const curve = new THREE.CatmullRomCurve3(newPoints, false, "catmullrom", 0);
    const newPoints2 = curve.getSpacedPoints(item.dividerNumber); //获取更多的点数
    item.geometry.setFromPoints(newPoints2);
  });
};
onMounted(() => {
  initial();
  // 所有站点标签
  tagAll();
  // 所有线条/文字/数据
  lineAll();
  // 飞线
  flyLine();

  // Vue标签转化
  vueTag();

  // 添加所有通讯事件
  eventBusInit();
});
// ----------------------------事件相关--------------------------

const eventBusInit = () => {
  EventBus.on("onStationClick", (option) => {
    console.log(option);
  });
};
const eventBusDestroy = () => {
  EventBus.off("onStationClick");
};

// ----------------------------重置相机--------------------------
const resetCamera = (frame) => {
  console.log(controls);
  console.log(camera.position);

  camera.position.set(0, 200, 0);
  // gsap.to(camera.position,{duration:1, x:0, z:0})
  // camera.lookAt(0, 0, 0); // 有控制器这句话就无效
  controls.target.set(0, 0, 0);
  // controls.update();

  // console.log(camera.position);
};
// ----------------------------表单相关--------------------------

const form = reactive({ x: 0, z: 0 });

// ----------------------------监听网页拉伸--------------------------
window.addEventListener("resize", () => {
  // Update sizes
  sizes.width = baseBox.clientWidth;
  sizes.height = baseBox.clientHeight;
  // Update camera
  camera.aspect = sizes.width / sizes.height;
  camera.updateProjectionMatrix();
  // Update renderer
  css3dRenderer.setSize(sizes.width, sizes.height);
  renderer.setSize(sizes.width, sizes.height);
  renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
});
// ----------------------------点击射线检测--------------------------
// 由于tagGroup中CSS转换的元素添加了点击事件会使得双击无效
// 所以应该尽量排好模型线路再打开CSS元素的事件
window.addEventListener("dblclick", (e) => {
  const result = utils.choose(e, sizes, camera, [mesh]); //射线拾取结果
  const point = result[0].point;
  form.x = point.x;
  form.z = point.z;
});

onUnmounted(() => {
  // 清楚所有通信事件
  eventBusDestroy();
  // if (tagGroup.children.length) utils.disposeGroup(mapGroup);
  // if (lineGroup.children.length) utils.disposeGroup(lineGroup);
  // if (flyGroup.children.length) utils.disposeGroup(meshGroup);
  // if (boxGroup.children.length) utils.disposeGroup(flyGroup);
  // if (tagGroup.children.length) utils.disposeGroup(tagGroup);
  // if (mainDataGroup.children.length) utils.disposeGroup(nameGroup);
  // if (subDataGroup.children.length) utils.disposeGroup(circleGroup);
});
</script>
<style lang="scss" scoped>
.base {
  width: 100%;
  height: 100%;
  background-color: #ffffff;
  position: relative;
  .test {
    position: absolute;
    padding: 20px;
    background-color: #1f288b;
    // pointer-events: none;
    text-align: center;
    color: #fff;
    box-sizing: border-box;
    z-index: 2;
  }
  #webgl {
    width: 100%;
    height: 100%;
  }
  .pannel {
    position: absolute;
    left: 0;
    top: 0;
    z-index: 1;
    width: 330px;
    // padding-left: 20px;
    min-height: 60px;
    border-bottom-right-radius: 40px;
    background-color: #222a99;
    color: #fff;
    padding: 10px;
    font-size: 14px;
    @include flex(column, flex-start, flex-start);
  }
}
.btn {
  cursor: pointer;
  color: #030738;
}
</style>